
# Data preparation tool
# ---------------------------------------------------------------------------
# Parameters
#  k - how many elements should be elminated from the set
#  input.file - file containing data
#  output.test.file - file containing test set extracted from data
#  output.base.file - file containing the rest of the set
# ---------------------------------------------------------------------------
# Example usage:
# eliminate.k.newest(300,"100k/u.data","100k/uk.test","100k/uk.base");
# ---------------------------------------------------------------------------
eliminate.k.newest<-function(k,input.file="u.data",output.test.file="uk.test",output.base.file="uk.base")
{
	# Reads data
	data<-read.table(input.file);

	# Sorts data by time
	data.by.time <- data[order(data[,4],decreasing =TRUE), ]

	# Picks first k and sorts it
	data.first.k <- data.by.time[1:k,];
	data.first.k.sorted <- data.first.k[order(data.first.k[,1]), ]

	# Sots the rest of the data 
	data.rest <- data.by.time[k+1:nrow(data),]
	data.rest.sorted <- data.rest[order(data.rest[,1]), ]
	
	# Writes otuput
	write.table(data.first.k.sorted,output.test.file,sep="\t");
	write.table(data.rest.sorted,output.base.file,sep="\t");
}



# Support function for data preparation. Analizes data and decides weather
# put it in the test or base global table
# ---------------------------------------------------------------------------
# Parameters:
# row - data frame row containig currently analised data
# picked.items - chosen users - part of it later would be included in the test file
# picked.users.items -  - items of picked users that should be included in base set
# ---------------------------------------------------------------------------
# Usage:
# called automaticaly by create.test.files
return.test.row<-function(row,picked.users.items,picked.users)
{
	curr.user<-row[1]
	curr.item<-row[2]
	if(curr.user %in% picked.users)
	{
		#Retrieves data about users from the list
		picked<-picked.users.items[[as.character(curr.user)]]

		# Chcecks for the negative values
		if(sum(curr.item %in% picked))
		{
			#  Connecting tables
			test<<-rbind(test,row);
			return();
		}	
		base<<-rbind(base,row);
	}
	
}

# Support function finding users with at least m films 
# ---------------------------------------------------------------------------
# Parameters
# k - how many users to search
# m - how many items minimally user should have
# data - date.frame being searched
# maxtry - how many times algorithm tries to fin users
# ---------------------------------------------------------------------------
# Sample usage
# called autoomaticaly by using.strategy.pick.k.with.n

find.k.users.with.at.least.m<-function(k,m,data,maxtry)
{
    trynr<- 0;
    repeat
    {
	    # Pickes users sample
	    users.sample<-sample(levels(factor(data$user)),k)
	    # Increase nr of tries
	    trynr<-trynr+1;
	    data.of.picked<-data[data$user %in% users.sample,]
	    data.of.picked.userf<-factor(data.of.picked$user);
	    # Chcecks m fils condition
	    if (!prod(summary(data.of.picked.userf) < m)) return(data.of.picked);
	    if (trynr > maxtry) return();
    }
    
}


# Support function for concatenating results and writing result csv2 files
# ---------------------------------------------------------------------------
# Parameters
# output.test.file - name of the test output file
# output.base.file - name of the base output file
# data - date.frame being searched
# picked.users.items - items of chosen users
# users.sample - chosen users
# ---------------------------------------------------------------------------
# Sample usage
# called autoomaticaly by using.strategy.pick.k.with.n
create.test.files<-function(output.test.file,output.base.file,data,picked.users.items,users.sample)
{
	# Creating global variables
	test<<-data.frame(user=numeric(0),item=numeric(0),rating=numeric(0),time=numeric(0));
	base<<-data.frame(user=numeric(0),item=numeric(0),rating=numeric(0),time=numeric(0));

	# Classifying rows to test and base test
	apply(data,1,return.test.row,picked.users.items,users.sample)
  
	# Writing to test file
	test<-test[order(test[,1],test[,2]), ]
	colnames(test)=c("user","item","rating","time");
	write.csv2(test,output.test.file,row.names=FALSE)

	# Writing to base file  (and bindnig)
	data.rest<-data[!(data$user %in% users.sample),]
	colnames(data.rest)=c("user","item","rating","time");
	colnames(base)=c("user","item","rating","time");
	print(base)
	print(data.rest)
	base.final<-rbind(base,data.rest)
	base.final<-base.final[order(base.final[,1],base.final[,2]), ]
	print(base.final)
	#colnames(base.final)=c("user","item","rating","time");
	write.csv2(base.final,output.base.file,row.names=FALSE)
}


# Strategy function picking n items using info about them from user.data data.frame
# ---------------------------------------------------------------------------
# Parameters
# user.data - user data frame
# n - how many items should be picked
# ---------------------------------------------------------------------------
# called automatically by pick.k.users.with.n.random.items
give.random.n.items<-function(user.data,n)
{
return(sample(user.data$item,n))
}

# Strategy function picking n items using info about them from user.data data.frame.
# Picks n items with the newest rating
# ---------------------------------------------------------------------------
# Parameters
# user.data - user data frame
# n - how many items should be picked
# ---------------------------------------------------------------------------
# called automatically by pick.k.users.with.n.newest.items
give.newest.n.items<-function(user.data,n)
{
	# Sort bys time
	data.by.time <- user.data[order(user.data[,4],decreasing =TRUE), ]
	data.first.n <- data.by.time[1:n,];
	data.first.n.sorted <- data.first.n[order(data.first.n[,1]), ]
	#print(data.first.n.sorted[1:n,])
	return(data.first.n[,2])
}

# Function that applies given strategy of picking items of users.
# ---------------------------------------------------------------------------
# Parametes
# chosen.strategy - method of picking users (both above)
# k - how many users should be picked
# n - how many items for each user
# input.file - file with data
# output.test.file - output file name for tests
# otuput.base.file - output file name for base
# margin - how many items after excluding those for test should user have
# maxtry - how many times method shoulld try to acquire appropriate data
# ---------------------------------------------------------------------------
# Usage:
# Called automaticaly by wrapper functions
using.strategy.pick.k.with.n<-function(chosen.strategy,k,n,input.file,output.test.file,output.base.file,margin,maxtry)
{
	# Reading input data
	data<-read.table(input.file);
	colnames(data)<-c("user","item","rating","time");
	userf<-factor(data$user);
	
	# Searching of the users
	data.of.picked<-find.k.users.with.at.least.m(k,margin+n,data,maxtry);

	# Applying given strategy
	picked.users.items<-by(data.of.picked,factor(data.of.picked$user),chosen.strategy,n,simplify=TRUE)

	# Creating test files
	create.test.files(output.test.file, output.base.file , data, picked.users.items , levels(factor(data.of.picked[,1])));
}


# Final Wrapper function for using. Should be available to final user
# Picks randomly k users with at least n items
# ---------------------------------------------------------------------------
# Parameters:
# k - how many users pick
# n - how many items for each user
# input.file - filename of data
# output.test.file - output file name for tests
# otuput.base.file - output file name for base
# margin - how many items after excluding those for test should user have
# maxtry - how many times method shoulld try to acquire appropriate data
# ---------------------------------------------------------------------------
# Sample usage:
# pick.k.users.with.n.random.items(100,5)
pick.k.users.with.n.random.items<-function(k,n,input.file="100k/u.data",output.test.file="100k/uk.test",output.base.file="100k/uk.base"
					    ,margin=9,maxtry=10)
{
	using.strategy.pick.k.with.n(give.random.n.items,k,n,input.file,output.test.file,output.base.file,margin,maxtry)
}



# Final Wrapper function for using. Should be available to final user
# Picks randomly k users with at least n items. For each user picks only 
# these with newest ranks
# ---------------------------------------------------------------------------
# Parameters:
# k - how many users pick
# n - how many items for each user
# input.file - filename of data
# output.test.file - output file name for tests
# otuput.base.file - output file name for base
# margin - how many items after excluding those for test should user have
# maxtry - how many times method shoulld try to acquire appropriate data
# ---------------------------------------------------------------------------
# Sample usage:
# pick.k.users.with.n.newest(100,5)
pick.k.users.with.n.newest<-function(k,n,input.file="100k/u.data",output.test.file="`100k/uk.test",output.base.file="100k/uk.base"
				      ,margin=9,maxtry=10)
{	
	using.strategy.pick.k.with.n(give.newest.n.items,k,n,input.file,output.test.file,output.base.file,margin,maxtry)
}
